/*
 * Copyright (C) 2011-2012 Wojciech Dzierżanowski
 * See LICENSE.txt for licensing details.
 */

package wdzierzan.downstream.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.NotificationManager;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.util.TypedValue;
import android.view.*;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import wdzierzan.downstream.android.servermanager.Server;
import wdzierzan.downstream.android.servermanager.ServerManager;
import wdzierzan.downstream.core.Streamer;

import java.io.File;
import java.io.IOException;

public class FileListActivity extends Activity {

    private static final String EXTRA_PATH = "path";

    private Streamer streamer = null;
    
    private boolean started = false;

    private Dialog about_dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LoggingAdapter.initLogging();
        ServerManager.getInstance().initialize(this);
    }

    @Override
    protected void onStart() {
        started = true;
        super.onStart();

        if (handleStreamerServiceActions())
            return;

        if (ensureHasActiveServer())
            doStart();
    }

    /**
     * @return whether the action is considered fully handled
     */
    private boolean handleStreamerServiceActions() {
        if (StreamerService.ACTION_CANCEL.equals(getIntent().getAction())) {
            askCancelStreaming();
            return true;
        }
        if (StreamerService.ACTION_CLEAR_OK.equals(getIntent().getAction())) {
            ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(StreamerService.NOTIFICATION_ID);
            finish();
            return true;
        }
        if (StreamerService.ACTION_CLEAR_ERROR.equals(getIntent().getAction())) {
            ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(StreamerService.NOTIFICATION_ID);
        }
        return false;
    }

    /**
     * @return whether there is an active server available (we can list files)
     */
    private boolean ensureHasActiveServer() {
        Server activeServer = ServerManager.getInstance().getActiveServer();
        if (activeServer != null)
            return true;

        if (ServerManager.getInstance().getAllServers().length > 1)
            showServerSwitcher();
        else
            startServerConfigActivity();

        return false;
    }

    private void doStart() {

        boolean needsRefresh = false;
        Streamer newStreamer = ServerManager.getInstance().acquireStreamer();

        if (newStreamer != streamer || newStreamer == null) {
            needsRefresh = true;
        } else {
            String intentPath = getIntent().getStringExtra(EXTRA_PATH);
            if (intentPath != null) {
                try {
                    intentPath = new File(intentPath).getCanonicalPath();
                    String serverPath = new File(ServerManager.getInstance().getActiveServer().getMusicPath())
                            .getCanonicalPath();
                    needsRefresh = !intentPath.startsWith(serverPath);
                } catch (IOException e) {
                    needsRefresh = true;
                }
            }
       }

        if (streamer != null)
            ServerManager.getInstance().releaseStreamer(streamer);
        streamer = newStreamer;

        if (needsRefresh) {
            if (ServerManager.getInstance().getAllServers().length == 0) {
                startServerConfigActivity();
                return;
            }

            if (streamer != null) {
                initContentView();
            } else {
                Runnable onSuccess = new Runnable() {
                    public void run() {
                        if (started)
                            initContentView();
                    }
                };
                initializeStreamer(R.string.connecting, onSuccess);
            }
        }
    }

    @Override
    protected void onStop() {
        super.onStop();

        started = false;

        if (about_dialog != null) {
            about_dialog.dismiss();
            about_dialog = null;
        }
    }

    @Override
    protected void onDestroy() {
        if (streamer != null)
            ServerManager.getInstance().releaseStreamer(streamer);
        ServerManager.getInstance().dispose();
        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.switch_server:
                showServerSwitcher();
                return true;
            case R.id.manage_servers:
                startServerConfigActivity();
                return true;
            case R.id.about:
                showAboutDialog();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void showServerSwitcher() {
        Server[] servers = ServerManager.getInstance().getAllServers();
        final int active = ServerManager.getInstance().getActiveServerIndex();
        assert(servers.length > 1);
        String[] names = new String[servers.length];
        for (int i = 0; i < servers.length; i++)
            names[i] = servers[i].getName();

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle(R.string.server_switcher_title);
        builder.setSingleChoiceItems(names, active, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                ServerManager.getInstance().setActiveServerIndex(which);
                dialog.dismiss();
                getIntent().removeExtra(EXTRA_PATH);
                doStart();
            }
        });
        AlertDialog dialog = builder.create();
        dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        dialog.show();
    }

    private void startServerConfigActivity() {
        Intent intent = new Intent(this, ServerManagerActivity.class);
        startActivity(intent);
    }

    private void initContentView() {
        if (streamer == null)
            streamer = ServerManager.getInstance().acquireStreamer();

        String path = getIntent().getStringExtra(EXTRA_PATH);
        if (path == null)
            path = ServerManager.getInstance().getActiveServer().getMusicPath();

        initContentView(path);
    }

    private void initContentView(String path) {
        assert(streamer != null);
        setContentView(createTextView(R.string.loading));
        new ListFilesTask().execute(path);
    }

    private void initContentView(String path, String[] childPaths) {
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);

        if (childPaths != null) {
            if (childPaths.length > 0) {
                for (String childPath : childPaths) {
                    TextView text = createTextView(childPath);
                    final String fullChildPath = path + '/' + childPath;
                    if (childPath.endsWith("/")) {
                        text.setCompoundDrawablesWithIntrinsicBounds(
                                getResources().getDrawable(android.R.drawable.sym_contact_card),
                                null, null, null);
                        text.setOnClickListener(new OnClickListener() {
                            public void onClick(View view) {
                                startChildActivity(fullChildPath.substring(0, fullChildPath.length() -1));
                            }
                        });
                    }
                    text.setOnLongClickListener(new View.OnLongClickListener() {
                        public boolean onLongClick(View view) {
                            askStartStreaming(fullChildPath);
                            return true;
                        }
                    });
                    layout.addView(text);
                }
            } else {
                layout.addView(createTextView(R.string.empty_list));
            }
        } else {
            layout.addView(createTextView(R.string.connecting_failed));
        }

        ScrollView scrollView = new ScrollView(this);
        scrollView.addView(layout);
        setContentView(scrollView);
    }

    private TextView createTextView(int textResourceId) {
        return createTextView(getString(textResourceId));
    }

    private TextView createTextView(String text) {
        TextView view = new TextView(this);
        view.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
        view.setText(text);
        return view;
    }

    private void initializeStreamer(int reasonTextResourceId, Runnable onSuccess) {
        setContentView(createTextView(reasonTextResourceId));
        Runnable onFailure = new Runnable() {
            public void run() {
                if (started)
                    setContentView(createTextView(R.string.connecting_failed));
            }
        };
        OnCancelListener onCancel = new OnCancelListener() {
            public void onCancel(DialogInterface di) {
                setContentView(createTextView(R.string.must_authenticate));
            }
        };
        ServerManager.getInstance().initializeStreamer(this, onSuccess, onFailure, onCancel);
    }

    private void startChildActivity(String path) {
        Intent subdirIntent = new Intent(this, getClass());
        subdirIntent.putExtra(EXTRA_PATH, path);
        startActivity(subdirIntent);
    }

    private void startStreamerService(final String path) {
        Streamer probe_streamer = null;
        try {
            probe_streamer = ServerManager.getInstance().acquireStreamer();
            if (probe_streamer == null) {
                Runnable onSuccess = new Runnable() {
                    @Override
                    public void run() {
                        assert(started);
                        startStreamerService(path);
                        initContentView();
                    }
                };
                initializeStreamer(R.string.connecting, onSuccess);
                return;
            }
        } finally {
            if (probe_streamer != null)
                ServerManager.getInstance().releaseStreamer(probe_streamer);
        }

        Intent intent = new Intent(this, StreamerService.class);
        intent.putExtra(StreamerService.EXTRA_PATH, path);
        startService(intent);

        Toast.makeText(this, R.string.starting_download, Toast.LENGTH_SHORT).show();
    }

    private void askStartStreaming(final String path) {
        new AlertDialog.Builder(this)
                .setTitle(R.string.ask_start_streaming_title)
                .setMessage(R.string.ask_start_streaming_message)
                .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface di, int i) {
                            startStreamerService(path);
                        }
                    })
                .setNegativeButton(R.string.no, null)
                .create().show();
    }

    private void askCancelStreaming() {
        new AlertDialog.Builder(this)
                .setTitle(R.string.ask_cancel_title)
                .setMessage(R.string.ask_cancel_message)
                .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface di, int i) {
                            Intent cancel = new Intent(FileListActivity.this, StreamerService.class);
                            cancel.setAction(StreamerService.ACTION_CANCEL);
                            startService(cancel);
                            finish();
                        }
                    })
                .setNegativeButton(R.string.no,  new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface di, int i) {
                            finish();
                        }
                    })
                .create().show();
    }

    private void showAboutDialog() {
        about_dialog = new Dialog(this);
        about_dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
        about_dialog.setTitle(R.string.about);
        about_dialog.setContentView(R.layout.about);
        
        String name = getString(R.string.app_name);
        String version;
        try {
            version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
        } catch (NameNotFoundException ex) {
            throw new RuntimeException(ex);
        }
        ((TextView) about_dialog.findViewById(R.id.name)).setText(
                getString(R.string.app_name_and_version, name, version));

        // Make link clickable.
        ((TextView) about_dialog.findViewById(R.id.about_text)).setMovementMethod(LinkMovementMethod.getInstance());

        about_dialog.show();
    }

    private class ListFilesTask extends AsyncTask<String, Void, String[]> {
        private String path;
        private IOException exception;

        @Override
        protected String[] doInBackground(String... paths) {
            this.path = paths[0];
            String[] files = null;
            try {
                if (streamer != null)
                    files = streamer.listFiles(paths[0]);
            } catch (IOException e) {
                exception = e;
            }
            return files;
        }

        @Override
        protected void onPostExecute(String[] childPaths) {
            if (!started)
                return;

            if (exception != null)
                new AlertDialog.Builder(FileListActivity.this)
                        .setTitle(R.string.error)
                        .setMessage(exception.toString())
                        .create().show();

            initContentView(path, childPaths);
        }
    }
}
